package cn.edu.sdjzu.knoverse.service.impl;

import cn.edu.sdjzu.knoverse.constant.EdgeConstant;
import cn.edu.sdjzu.knoverse.model.entity.kg.CaseNode;
import cn.edu.sdjzu.knoverse.model.entity.kg.ComponentNode;
import cn.edu.sdjzu.knoverse.model.entity.kg.FileNode;
import cn.edu.sdjzu.knoverse.model.entity.kg.KnowledgeNode;
import cn.edu.sdjzu.knoverse.model.entity.system.Files;
import cn.edu.sdjzu.knoverse.model.vo.kg.FileInfoVo;
import cn.edu.sdjzu.knoverse.repository.CaseRepository;
import cn.edu.sdjzu.knoverse.repository.ComponentRepository;
import cn.edu.sdjzu.knoverse.repository.FileNodeRepository;
import cn.edu.sdjzu.knoverse.repository.KnowledgeRepository;
import cn.edu.sdjzu.knoverse.service.ComponentService;
import cn.edu.sdjzu.knoverse.service.FileNodeService;
import cn.edu.sdjzu.knoverse.service.FilesService;
import cn.edu.sdjzu.knoverse.utils.exception.CustomException;
import cn.edu.sdjzu.knoverse.utils.minio.MinioUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ComponentServiceImpl implements ComponentService {

    private final ComponentRepository componentRepository;
    private final CaseRepository caseRepository;
    private final KnowledgeRepository knowledgeRepository;
    private final FileNodeService fileNodeService;
    private final FileNodeRepository fileNodeRepository;
    private final FilesService filesService;
    private final MinioUtil minioUtil;

    @Override
    @Transactional
    public ComponentNode createComponent(ComponentNode component, Long caseId) {
        // 检查案例是否存在
        CaseNode caseNode = caseRepository.findById(caseId)
                .orElseThrow(() -> new CustomException("案例不存在"));
        
        // 保存组件
        ComponentNode savedComponent = componentRepository.save(component);
        
        // 获取CASE_COMPONENT关系的基本信息
        EdgeConstant caseComponentEdge = EdgeConstant.CASE_COMPONENT;
        String edgeName = caseComponentEdge.getName();
        String edgeDescription = caseComponentEdge.getDescription();
        
        // 创建案例到组件的关系
        componentRepository.createCaseComponentRelationship(
                caseId, 
                savedComponent.getNodeId(), 
                edgeName, 
                edgeDescription
        );
        
        return savedComponent;
    }

    @Override
    @Transactional
    public ComponentNode updateComponent(ComponentNode component) {
        ComponentNode existingComponent = getComponent(component.getNodeId());
        if (existingComponent == null) {
            throw new CustomException("组件不存在");
        }
        return componentRepository.save(component);
    }

    @Override
    @Transactional
    public void deleteComponent(Long id) {
        if (!componentRepository.existsById(id)) {
            throw new CustomException("组件不存在");
        }
        
        // 删除组件和文件之间的关系
        componentRepository.deleteComponentFileRelationships(id);
        
        // 删除组件和知识点之间的关系
        componentRepository.deleteComponentKnowledgeRelationships(id);
        
        // 删除组件
        componentRepository.deleteById(id);
    }

    @Override
    public ComponentNode getComponent(Long id) {
        ComponentNode component = componentRepository.findById(id)
                .orElseThrow(() -> new CustomException("组件不存在"));
        
        // 查询组件所属的案例
        CaseNode caseNode = componentRepository.findCaseByComponentId(id);
        
        return component;
    }

    @Override
    public Set<ComponentNode> getComponentsByCase(Long caseId) {
        // 检查案例是否存在
        if (!caseRepository.existsById(caseId)) {
            throw new CustomException("案例不存在");
        }
        
        // 获取案例下的所有组件
        return componentRepository.findByCaseId(caseId);
    }
    
    @Override
    @Transactional
    public void updateComponentFiles(Long componentId, List<Long> fileIds) {
        // 检查组件是否存在
        ComponentNode component = getComponent(componentId);
        
        // 删除组件的所有文件关系
        componentRepository.deleteComponentFileRelationships(componentId);
        
        // 获取COMPONENT_FILE关系的基本信息
        EdgeConstant fileEdge = EdgeConstant.COMPONENT_FILE;
        String edgeName = fileEdge.getName();
        String edgeDescription = fileEdge.getDescription();
        
        // 创建新的文件关系
        for (Long fileId : fileIds) {
            // 确保文件节点存在
            fileNodeService.saveFileNode(fileId);
            // 创建关系
            componentRepository.createComponentFileRelationship(componentId, fileId, edgeName, edgeDescription);
        }
    }
    
    @Override
    public Set<FileNode> getComponentFiles(Long componentId) {
        // 检查组件是否存在
        if (!componentRepository.existsById(componentId)) {
            throw new CustomException("组件不存在");
        }
        
        // 获取所有附件文件
        return fileNodeRepository.findComponentFiles(componentId);
    }
    
    @Override
    @Transactional
    public void updateRelatedKnowledge(Long componentId, List<Long> knowledgeIds) {
        // 检查组件是否存在
        ComponentNode component = getComponent(componentId);
        
        // 验证所有知识点是否存在
        for (Long knowledgeId : knowledgeIds) {
            if (!knowledgeRepository.existsById(knowledgeId)) {
                throw new CustomException("知识点不存在：" + knowledgeId);
            }
        }
        
        // 删除组件的所有知识点关联关系
        componentRepository.deleteComponentKnowledgeRelationships(componentId);
        
        // 获取RELATED关系的基本信息
        EdgeConstant relatedEdge = EdgeConstant.RELATED;
        String edgeName = relatedEdge.getName();
        String edgeDescription = relatedEdge.getDescription();
        
        // 创建新的知识点关联关系
        for (Long knowledgeId : knowledgeIds) {
            componentRepository.createComponentKnowledgeRelationship(componentId, knowledgeId, edgeName, edgeDescription);
        }
    }
    
    @Override
    public Set<KnowledgeNode> getRelatedKnowledge(Long componentId) {
        // 检查组件是否存在
        if (!componentRepository.existsById(componentId)) {
            throw new CustomException("组件不存在");
        }
        
        // 使用KnowledgeRepository中的方法直接获取完整的知识点信息
        return knowledgeRepository.findCompleteKnowledgeByComponentId(componentId);
    }
    
    @Override
    public Set<ComponentNode> getComponentsByKnowledge(Long knowledgeId) {
        // 检查知识点是否存在
        if (!knowledgeRepository.existsById(knowledgeId)) {
            throw new CustomException("知识点不存在");
        }
        
        // 获取所有关联组件
        return componentRepository.findByKnowledgeId(knowledgeId);
    }

    @Override
    public Set<FileInfoVo> getComponentFilesWithDetails(Long componentId) {
        // 获取组件的文件节点
        Set<FileNode> fileNodes = getComponentFiles(componentId);
        return convertToFileInfoVos(fileNodes);
    }

    /**
     * 将FileNode集合转换为FileInfoVo集合
     */
    private Set<FileInfoVo> convertToFileInfoVos(Set<FileNode> fileNodes) {
        Set<FileInfoVo> fileInfoSet = new HashSet<>();
        
        if (fileNodes != null && !fileNodes.isEmpty()) {
            // 提取所有FileNode的ID
            List<Long> fileIds = fileNodes.stream()
                    .map(FileNode::getFileId)
                    .collect(Collectors.toList());
            
            // 使用Mybatis Plus的批量查询功能获取完整文件信息
            List<Files> completeFiles = filesService.listByIds(fileIds);
            
            // 创建映射：fileId -> Files对象
            Map<Long, Files> fileMap = completeFiles.stream()
                    .collect(Collectors.toMap(Files::getId, file -> file));
            
            // 为每个文件创建FileInfoVo对象
            for (FileNode fileNode : fileNodes) {
                Files file = fileMap.get(fileNode.getFileId());
                if (file != null) {
                    // 构建FileInfoVo并设置基本信息
                    FileInfoVo fileInfoVo = FileInfoVo.builder()
                            .fileId(file.getId())
                            .filename(file.getFilename())
                            .filepath(file.getFilepath())
                            .fileSize(file.getFileSize())
                            .fileType(file.getFileType())
                            .downloadCount(file.getDownloadCount())
                            .createTime(file.getCreateTime())
                            .updateTime(file.getUpdateTime())
                            .build();
                    
                    // 使用MinioUtil生成文件的完整访问URL
                    if (file.getFilepath() != null) {
                        fileInfoVo.setUrl(minioUtil.getObjectNameFullPath(file.getFilepath()));
                    }
                    
                    fileInfoSet.add(fileInfoVo);
                }
            }
        }
        
        return fileInfoSet;
    }
} 